<?php

/**
 * User handling class, used for authentication, permissions handling and all other user related tasks
 * 
 * @author Marlon Brandon van der Linde
 * @copyright Marlon B van der Linde 2008
 * @version 1.00
 * @license http://www.opensource.org/licenses/mit-license.php MIT-License
*/
class MoltenBlobUser {

	/**
	 * The MoltenBlobDB object is stored here for db access
	 * @access private
	 * @var MoltenBlobDB
	 */
	private $db = null;

	/**
	 * Stores the current user's complete dataset
	 * these should equal the count and names of the DB fields
	 * @access protected
	 * @var array
	 */
	public $data = array(
		'id' => null,
		'username' => null,
		'password' => null,
		'name' => null,
		'lastname' => null,
		'email' => null,
		'prefs' => null,
		'disabled' => null,
		'lastlogin' => null,
		'level' => null,
	);


	/**
	 * Stores the current user's ID
	 * This might or might not be neccesary later
	 * @access protected
	 * @var int
	 */
	protected $uid = null;

	/**
	 * Stores the session name for later use, like logging users off/setcookie
	 * @access protected
	 */
	protected $session_name;


	/**
	 * Class Constructor
	 * @param MoltenBlobDB $dbobj Moltenblob Database object
	*/
	function __construct($dbobj) {
		$this->db = $dbobj;
	}


	/**
	 * Class Destructor
	 */
	function __destruct() {
	}

	
	/*
	 * A magic function to determine how this class will respond when accused of being a string :)
	 */
	function __toString() {
		// todo - return user fields, in an assoc array
	}


	/**
	 * Adds a new user account by inserting whatever data is set in $this->data
	 * add() checks for existing email or username existence before inserting.
	 */ 
	function add() {
		$u = $this->db->getRows(TBL_USER, 'username', $this->data['username']);
		// check if this user already exists
		if($u) {
			return false;
		} else {
			$fields = array();
			$vals = array();
			foreach($this->data as $k=>$v) {
				if($k!='id') {
					array_push($fields, $k);
					array_push($vals, $v);
				}
			}
			
			$id = $this->db->newRow(TBL_USER, $fields, $vals);
			if($id) 
				return $id;
			return false;
		}
	}


	/**
	 * Remove a user from the system completely. A better name would have been 'disable'.
	 * This will remove whoever is in $this->data['username'], if this username exists, so be SURE
	 * The user id of the removed/disabled user will be returned, or false on an error
	 * @see getUser()
	 * @return int
	 */
	function remove() {
		$u = $this->db->getRows(TBL_USER, 'username', $this->data['username']);

		if(!$u) {
			return false;
		}

		// now "remove" the user by resetting his password to a random value and setting a disabled flag
		$this->data['password'] = $this->random();
		$this->data['disabled'] = 1;
		if(!$this->update()) {
			return false;
		}
		return true;
	}


	/**
	 * Updates a user record. Use getUser() to fetch the update candidate, set the $this->data
	 * values appropriately, and then use update() to commit. Update requires that a username
	 * already exists in the database.
	 * @see getUser()
	 */
	function update() {
	
        $current = $this->get_user_fields();
		$f = array();
		$v = array();
 		$nochange = array('id','created');  // we DONT want to update these fields

 		foreach($current as $field => $value) {
			if(!in_array($field, $nochange)) {
				array_push($f, $field );
				array_push($v, $value );
			}
		}
		
		if($this->db->bumpRow(TBL_USER, $f, $v, $current['id'])) {
			return true;
		}
		return false;
	}


	/**
	 * Returns this user's level/roles (permissions)
	 * @todo extrawtf
	 */
	function getRoles() {
		// todo
	}


	/**
	 * Set user data in $data. This only sets $this->data values and does not commit to DB
	 * This might become redundant later.... 
	 * @param string $field Field to update in class var $data[field]
	 * @param string $value Value to insert into $field
	 * @return bool
	 */
	function set($field, $value) {
		if(array_key_exists($field, $this->data)) {
			if(!empty($value))
				$this->data[$field] = $value;
			return true;
		}
		return false;
	}


	/**
	 * Returns what is currently set in the dataset $data. 
	 * To return data from the actual database values, use getUser()
	 * @see getUser()
	 */
	function get_user_fields() {
		foreach($this->data as $k=>$v) {
			if(empty($v)) {
				if( $k =! 'id') {
					$this->data[$k] = 'Not Set';
				}
			}
		}
		return $this->data;
	}


	/**
	 * Fetch currently logged on user data from DB and store it inside $this->data
	 * Find user based on $this->data->id
	 */
	function getUser() {

		if(empty($this->uid)) { return false; }
		$row = $this->db->getRows(TBL_USER, 'id', $this->uid);
		if($row) {
			foreach($row[0] as $field=>$value) {
				$this->data[$field] = $value;
			}
		}
	}


	/**
	 * Fetch user data from DB and store it inside $this->data. Same as getUser() except we get the user
	 * by username instead of using the built-in ID
	 * @param string $username Username to fetch
	 * @return bool
	 */
	function getUserName($username) {
		$row = $this->db->getRows(TBL_USER, 'username', $username);

		if($row) {
			foreach($row[0] as $field=>$value) {
				$this->data[$field] = $value;
			}
			return true;
		}
		return false;
	}


	/**
	 * Authenticates the current user by taking username and password values, authenticating and returning bool
	 * This function should set up the session, $this->uid etc
	 * @param string $username Username to test
	 * @param string $password Password to test
	 * @return bool
	 */
	function auth($username, $password) {
		$u = $this->db->getRows(TBL_USER, 'username', $username);	
		
		if($u) {
			if( strcmp($u[0]['password'], $this->babble($password)) == 0) {

				$_SESSION['username'] = $username;
				$_SESSION['loggedin'] = 1;
				$_SESSION['logintime'] = date('Y-m-d G:i:s');

				// check if this user has admin privs and set ['admin']

				$this->session_name = session_name();

				return true;	// username and password matched

			} else {
				$this->logoff(); 	// pass didnt match, clear sessions
				return false;
			}

		} else {
			$this->logoff();	// user not found, clear sessions
			return false;
		}
	}


	/**
	 * Logs a user off by destroying the current session values
	 * Returns true on logout or false otherwise
	 * @return bool
	 * @todo This works, but something is pukey - fixme
	 */
	function logoff() {
		session_destroy();
		if ( isset( $_COOKIE[ $this->session_name ] ) ) {
			if ( setcookie(session_name(), '', time()-3600, '/') ) {
				return true;
			} else {
				return false;
			}
		}
	}


	
	/**
	 * Checks if someone is logged in and prepares the session, etc
	 * @return bool
	 */
	function loggedin() {
	}


	/**
	 * Checks if this/current user is administrative and returns a bool.
	 * @return bool
	 */
	function isadmin() {
		if($_SESSION['admin'] == 1 ) { return true; }
		return false;
	}

	
	/**
	 * Encryption function for passwords etc.
	 * This is "functioned" to make changing the hash function/algorithms used easier
	 * @param string $string The string to hash/encrypt
	 * @return string
	 */
	function babble($string) {
		return md5($string);
	}


	/**
	 * Return a random number based on a seed of microseconds
	 * Use this for passwords or parrot sacrifice
	 * @return int
	 */
	function random() {
		list($usec, $sec) = explode(' ', microtime());
		return (float) $sec + ((float) $usec * 100000);
	}














}
?>
